package org.demo.java2d;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.demo.java2d.data.TreeNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * 
 * @author  
 * @date    2010-5-12
 * @file    org.demo.java2d.Java2DTree.java
 */
public class Java2DTree {

	private List<TreeNode> left = new ArrayList<TreeNode>();
	private List<TreeNode> right = new ArrayList<TreeNode>();
	// 图像上方空白
	private int paddingTop = 100;
	// 图像左边空白
	private int paddingLeft = 20;
	// 树节点的高度
	private int nodeHeight = 22;
	// 内存图像
	private BufferedImage image = null;
	// 图像宽度
	private int imgWidth = 1000;
	// 图像高度
	private int imgHeight = 600;
	// 背景色
	private Color backgroundColor = Color.WHITE;
	// 前景色
	private Color foregroundColor = Color.BLACK;
	// 背景线颜色
	private Color backLineColor = new Color(216, 216, 219);
	// 连线颜色
	private Color lineColor = Color.BLUE;
	// 字体
	private Font defaultFont = new Font("宋体", Font.BOLD, 18);
	
	/**
	 * 主函数
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		String filePath = "D:/workspace/eclipse_inspur/adapter_config_pro/WebContent/WEB-INF/ra/I_SPYW_HEALTH_REGISTER/option/mapping.xml";
		String pngPath = "d:\\Temp\\mapping.png";
		
		Java2DTree t = new Java2DTree();
		t.readXml(filePath);
		t.drawImage();
		t.save(pngPath);
	}
	/**
	 * 读取 xml 文件
	 * @param filePath
	 * @throws Exception
	 */
	private void readXml(String filePath)throws Exception{
		// 
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.parse(new File(filePath));
		Element root = doc.getDocumentElement();
		
		int x = 0, y = 0;		
		// left tree
		List<Element> tmp_list = getChildren(root, "left");
		if (tmp_list.size() > 0){
			Element left_element = tmp_list.get(0);
			List<Element> table_list = getChildren(left_element, "table");
			for(Element ele : table_list){
				x = paddingLeft;
				y = left.size() * nodeHeight + paddingTop;
				add2TreeList(left, ele, x, y);
			}
		}
		
		// right tree
		tmp_list = getChildren(root, "right");
		if (tmp_list.size() > 0){
			Element right_element = tmp_list.get(0);
			List<Element> table_list = getChildren(right_element, "table");
			for(Element ele : table_list){
				x = imgWidth/2 + paddingLeft;
				y = right.size() * nodeHeight + paddingTop;
				add2TreeList(right, ele, x, y);
			}
		}
	}
	/**
	 * 在内存中绘图
	 */
	private BufferedImage drawImage(){
		this.image = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = image.createGraphics();
		
		// draw background
		drawBackground(g);		
		g.setColor(foregroundColor);
		g.setFont(defaultFont);
		
		FontMetrics fontMetrics = g.getFontMetrics(defaultFont);
		String data = null;
		int tnodeWidth = 0;
				
		// draw left tree		
		for (TreeNode tnode : left){
			data = tnode.getName() + " " + tnode.getDesc();
			tnodeWidth = fontMetrics.stringWidth(data);
			tnode.setWidth(tnodeWidth);
			g.drawString(data, tnode.getX(), tnode.getY());
		}
		
		// draw right tree
		for (TreeNode tnode : right){
			data = tnode.getName() + " " + tnode.getDesc();
			tnodeWidth = fontMetrics.stringWidth(data);
			tnode.setWidth(tnodeWidth);
			g.drawString(data, tnode.getX(), tnode.getY());
		}
		
		// draw line
		g.setColor(lineColor);
		int lineX1, lineY1, lineX2, lineY2;
		for (TreeNode tnode : left){
			String[] toNames = tnode.getTo().split(",");
			// 左边一个节点可以对应右边多个节点
			for (String toName : toNames){
				TreeNode rightNode = getRightNode(toName);
				if (rightNode == null){
					// not found mapping node
					continue;
				}
				lineX1 = tnode.getX() + tnode.getWidth() + 5;
				lineY1 = tnode.getY() - 10;
				lineX2 = rightNode.getX() - 5;
				lineY2 = rightNode.getY() - 10;
				g.drawLine(lineX1, lineY1, lineX2, lineY2);
			}
		}
		
		// return image
		g.dispose();
		return image;
	}
	/**
	 * 将图像保存到文件
	 * @param filePath
	 * @throws IOException
	 */
	private void save(String filePath) throws IOException{		
		ImageIO.write(image, "png", new File(filePath));
	}
	/**
	 * 获取子元素
	 * @param parent
	 * @param name
	 * @return
	 */
	private List<Element> getChildren(Element parent,String name){   
	    List<Element> list = new ArrayList<Element>();   
	    Node node = parent.getFirstChild();   
	    while(node != null){   
	        if(node instanceof Element){   
	            if(name.equals(((Element)node).getTagName())){   
	                list.add((Element)node);   
	            }   
	        }   
	        node = node.getNextSibling();   
	    }   
	    return list;   
	}
	/**
	 * 将子元素添加到 list 中
	 * @param list
	 * @param element
	 * @param x
	 * @param y
	 */
	private void add2TreeList(List<TreeNode> list, Element element, 
			int x, int y) {
		String name = element.getAttribute("name");
		String desc = element.getAttribute("desc");
		String to = element.getAttribute("to");
		
		TreeNode node = new TreeNode(name, desc, to);
		node.setX(x);
		node.setY(y);
		list.add(node);
		
		// 处理子元素
		int parentX = x;
		List<Element> sub_tables = getChildren(element, "table");
		for(Element sub : sub_tables){
			x = parentX + paddingLeft;
			y = list.size() * nodeHeight + paddingTop;
			add2TreeList(list, sub, x, y);
		}
	}
	/**
	 * 获取右边的树节点
	 * @param nodeName
	 * @return
	 */
	private TreeNode getRightNode(String nodeName){
		for (TreeNode tnode : right){
			if (nodeName.equals(tnode.getName())){
				return tnode;
			}
		}
		return null;
	}  
	/**
	 * 渲染背景
	 * @param g
	 */
	private void drawBackground(Graphics2D g){
		int gridWidth = 10, gridHeight = 10;
		
		// fill background
		g.setColor(backgroundColor);
		g.fillRect(0, 0, imgWidth, imgHeight);
		g.setColor(backLineColor);
		
		// draw horizontal lines
		int y = 0;
		while (y < imgHeight){
			g.drawLine(0, y, imgWidth, y);
			y += gridHeight;
		}
		
		// draw vertical lines
		int x = 0;
		while (x < imgWidth){
			g.drawLine(x, 0, x, imgHeight);
			x += gridWidth;
		}
		
		// draw center line
		Stroke oldStroke = g.getStroke();
		g.setStroke(new BasicStroke(2.0f));
		g.setColor(new Color(173, 205, 60));
		g.drawLine(imgWidth/2, 0, imgWidth/2, imgHeight);
		g.setStroke(oldStroke);
	}
}
